a11y: Handle stack case for addition/removal
authorMatthias Clasen <mclasen@redhat.com>
Thu, 22 Oct 2020 13:55:50 +0000 (09:55 -0400)
committerMatthias Clasen <mclasen@redhat.com>
Thu, 22 Oct 2020 14:06:06 +0000 (10:06 -0400)
Since we interpose stack pages as non-widget accessibles,
we need to tweak the signals we emit when their corresponding
widgets get added or removed.

gtk/a11y/gtkatspicontext.c

index a3b5d8bb22a7824997bd4f185ee767e4bc850a89..be3cb128e672fb619088242812d4f2086ef0feef 100644 (file)
@@ -1065,18 +1065,76 @@ gtk_at_spi_context_child_change (GtkATContext             *ctx,
 {
   GtkAtSpiContext *self = GTK_AT_SPI_CONTEXT (ctx);
   GtkAccessible *accessible = gtk_at_context_get_accessible (ctx);
-  GtkATContext *child_context;
+  GtkATContext *child_context = gtk_accessible_get_at_context (child);
+  GtkWidget *parent_widget;
+  GtkWidget *child_widget;
+  int idx = 0;
 
-  if (!GTK_IS_WIDGET (accessible))
+  if (!GTK_IS_WIDGET (accessible) || !GTK_IS_WIDGET (child))
     return;
 
-  child_context = gtk_accessible_get_at_context (child);
   if (child_context == NULL)
     return;
 
-  GtkWidget *parent_widget = GTK_WIDGET (accessible);
-  GtkWidget *child_widget = GTK_WIDGET (child);
-  int idx = 0;
+  parent_widget = GTK_WIDGET (accessible);
+  child_widget = GTK_WIDGET (child);
+
+  /* handle the stack page special case */
+  if (GTK_IS_WIDGET (child) &&
+      GTK_IS_STACK (gtk_widget_get_parent (GTK_WIDGET (child))))
+    {
+      GtkWidget *stack;
+      GtkStackPage *page;
+      GListModel *pages;
+
+      stack = gtk_widget_get_parent (GTK_WIDGET (child));
+      page = gtk_stack_get_page (GTK_STACK (stack), GTK_WIDGET (child));
+      pages = G_LIST_MODEL (gtk_stack_get_pages (GTK_STACK (stack)));
+      idx = 0;
+      for (guint i = 0; i < g_list_model_get_n_items (pages); i++)
+        {
+          GtkStackPage *item = g_list_model_get_item (pages, i);
+
+          g_object_unref (item);
+
+          if (!gtk_accessible_should_present (GTK_ACCESSIBLE (item)))
+            continue;
+
+          if (item == page)
+            break;
+
+          idx++;
+        }
+      g_object_unref (pages);
+
+      if (change & GTK_ACCESSIBLE_CHILD_CHANGE_ADDED)
+        {
+          emit_children_changed (GTK_AT_SPI_CONTEXT (gtk_accessible_get_at_context (GTK_ACCESSIBLE (stack))),
+                                 GTK_AT_SPI_CONTEXT (gtk_accessible_get_at_context (GTK_ACCESSIBLE (page))),
+                                 idx,
+                                 GTK_ACCESSIBLE_CHILD_STATE_ADDED);
+
+          emit_children_changed (GTK_AT_SPI_CONTEXT (gtk_accessible_get_at_context (GTK_ACCESSIBLE (page))),
+                                 GTK_AT_SPI_CONTEXT (gtk_accessible_get_at_context (child)),
+                                 0,
+                                 GTK_ACCESSIBLE_CHILD_STATE_ADDED);
+        }
+
+      if (change & GTK_ACCESSIBLE_CHILD_CHANGE_REMOVED)
+        {
+          emit_children_changed (GTK_AT_SPI_CONTEXT (gtk_accessible_get_at_context (GTK_ACCESSIBLE (page))),
+                                 GTK_AT_SPI_CONTEXT (gtk_accessible_get_at_context (child)),
+                                 0,
+                                 GTK_ACCESSIBLE_CHILD_STATE_REMOVED);
+          emit_children_changed (GTK_AT_SPI_CONTEXT (gtk_accessible_get_at_context (GTK_ACCESSIBLE (stack))),
+                                 GTK_AT_SPI_CONTEXT (gtk_accessible_get_at_context (GTK_ACCESSIBLE (page))),
+                                 idx,
+                                 GTK_ACCESSIBLE_CHILD_STATE_REMOVED);
+
+        }
+
+      return;
+    }
 
   if (gtk_widget_get_parent (child_widget) != parent_widget)
     {